﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Channels.Http;
using System.Net;
using System.Threading;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Runtime.Remoting.Channels;
using RemoteObject;

namespace AllInOne
{
    class CloudService
    {
        static Dictionary<long, DownloadJob> cloudFileDictionary = new Dictionary<long, DownloadJob>();

        public static string IPAddress;
        static String RemoteServerUrl = "ServiceURLTcp";
        static int BlockSize = 1024 * 1024;


        [Serializable]
        public class BlockInfo
        {
            public int blockID, originPos, currentPos, remainDataLength;

        }

        public enum Status
        {
            Working,
            Pause,
            Completed
        }

        //debug use only
        static void PrintProgress(BlockInfo blockinfo)
        {
            double finishedLength = blockinfo.currentPos - blockinfo.originPos;
            double totalLength = blockinfo.remainDataLength + finishedLength;
            double result = finishedLength / totalLength * 100;
            //Console.WriteLine("Block [" + blockinfo.blockID + "] --- " + result.ToString("f1") + " %");
            if (result == 100) Console.WriteLine("Block [" + blockinfo.blockID + "] --- Completed");
        }
        //debug use only

        static void Main(string[] args)
        {
            IPAddress = Dns.GetHostByName(Dns.GetHostName()).AddressList[0].ToString();
            Console.WriteLine("Welcome {0}.", IPAddress);
            Console.Write("Is this cloud server?[y|n] ");
            String answer = Console.ReadLine().ToString();
            if (answer == "y")
            {                
                Common.CloudServerURL = String.Format("tcp://{0}:10001/RemoteObject.MyRemoteObject", IPAddress);
            }
            else
            {
                Console.Write("Please define the cloud server ip:");
                String ip = Console.ReadLine().ToString();
                Common.CloudServerURL = String.Format("tcp://{0}:10001/RemoteObject.MyRemoteObject", ip);
            }


            // **********LOCAL SERVER STARTUP********** //
            TcpChannel chanTcp = new TcpChannel(/*tcpPort*/ 10001);
            //HttpChannel chanHttp = new HttpChannel(/*httpPort*/ 10002);       

            ChannelServices.RegisterChannel(chanTcp, false);
            //ChannelServices.RegisterChannel(chanHttp, false);     
            Console.WriteLine("The name of the TCPChannel is {0}.",
                chanTcp.ChannelName);
            Console.WriteLine("The priority of the TCPChannel is {0}.",
                chanTcp.ChannelPriority);
            Console.WriteLine("The name of the HttpChannel is {0}.",
                chanTcp.ChannelName);
            Console.WriteLine("The priority of the HttpChannel is {0}.",
                chanTcp.ChannelPriority);
            RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemoteObject.MyRemoteObject), "RemoteObject.MyRemoteObject", WellKnownObjectMode.Singleton);
            RemoteObject.MyRemoteObject.OnUploadRequest += new RemoteObject.MyRemoteObject.MessageHandler(Request_OnUploadRequest);
            RemoteObject.MyRemoteObject.OnDistributeRequest += new RemoteObject.MyRemoteObject.MessageHandler(Request_OnDistributeRequest);
            RemoteObject.MyRemoteObject.OnStopUploadRequest += new RemoteObject.MyRemoteObject.MessageHandler2(Request_OnStopUploadRequest);
            RemoteObject.MyRemoteObject.OnSyncRequest += new RemoteObject.MyRemoteObject.MessageHandler3(Request_OnSyncRequest);
            RemoteObject.MyRemoteObject.OnJobDistributionRequest += new RemoteObject.MyRemoteObject.MessageHandler4(Request_OnJobListRequest);
            RemoteObject.MyRemoteObject.OnDistributedJobRequest += new RemoteObject.MyRemoteObject.MessageHandler5(Request_DistributedJob);
            // **********LOCAL SERVER STARTUP********** //

            // LOCAL CLIENT INIT //
            //String fnRemote = @"e:\test.iso";
            //String fnLocal = @"e:\down\test.iso";
            String cloudPath = @"C:\c\";

            while (true)
            {
                Console.WriteLine();
                Console.WriteLine("===============================================================");
                Console.WriteLine("==  [DOWN]:download;  [DOWNDIS]:download a distributed file; ==");
                Console.WriteLine("==  [UP]:upload;  [DIS]:distribute;  [SHOW]:show file list;  ==");
                Console.WriteLine("==  [QUIT]:quit                                              ==");
                Console.WriteLine("===============================================================");
                string input = Console.ReadLine();
                if (String.Compare(input, "DOWN", true) == 0)
                {
                    Console.Write("File name: ");
                    string name = Console.ReadLine();
                    Console.WriteLine("PROCESSING: {0} {1}", input, name);
                    DownloadJob downloadJob = new DownloadJob(String.Concat(cloudPath, name), String.Concat(cloudPath, name), Common.CloudServerURL);
                    Thread thread = new Thread(new ThreadStart(downloadJob.StartDownload));
                    thread.Start();               
                }
                else if (String.Compare(input, "DOWNDIS", true) == 0)
                {
                    Console.Write("File name: ");
                    string name = Console.ReadLine();
                    Console.WriteLine("PROCESSING: {0} {1}...", input, name);
                    DistributedFileRequestor disFileReq = new DistributedFileRequestor(name);
                    Thread thread = new Thread(new ThreadStart(disFileReq.Run));
                    thread.Start();
                }
                else if (String.Compare(input, "UP", true) == 0)
                {
                    Console.Write("File name: ");
                    string name = Console.ReadLine();
                    Console.WriteLine("PROCESSING: {0} {1}...", input, name);
                    UploadRequestor upReq = new UploadRequestor(String.Concat(cloudPath, name), String.Concat(cloudPath, name));
                    Thread thread = new Thread(new ThreadStart(upReq.StartUpload));
                    thread.Start();
                }
                else if (String.Compare(input, "DIS", true) == 0)
                {
                    Console.Write("File name: ");
                    string name = Console.ReadLine();
                    Console.WriteLine("PROCESSING: {0} {1}...", input, name);
                    DistributeRequestor disReq = new DistributeRequestor(String.Concat(cloudPath, name), String.Concat(cloudPath, name));
                    Thread thread = new Thread(new ThreadStart(disReq.Run));
                    thread.Start();
                }
                else if (String.Compare(input, "SHOW", true) == 0)
                {
                    List<DownloadJob> jobList = FileDistributionRequestor.getInstance().GetFileDistributionInfo();
                    if (jobList.Count == 0)
                    {
                        Console.WriteLine();
                        Console.WriteLine("******FILE LIST EMPTY******");
                        Console.WriteLine();
                    }
                    else
                    {
                        Console.WriteLine("******FILE LIST START******");
                        foreach (DownloadJob job in jobList)
                        {
                            Console.WriteLine();
                            Console.WriteLine("File Name:{0}, Size:{1} MB, Status:{2}", job.GetJobName(), job.GetFileSizeInMB(), job.GetStatus());
                        }
                        Console.WriteLine();
                        Console.WriteLine("*******FILE LIST END*******");
                    }
                }
                else if (String.Compare(input, "QUIT", true) == 0)
                {
                    break;
                }
                else
                {
                    Console.WriteLine("NO SUCH COMMOND: \"{0}\". ", input);
                }

            }
            

            ///////////////////For Debug/////////////////////////////
            //Console.WriteLine("Press any key to exit!");
           //System.Console.ReadLine();
        }

        public static void Request_OnUploadRequest(string fnRemote, string fnLocal, string ip, long jobID) //
        {
            //init downloader on host
            DownloadJob downloadJob = new DownloadJob(fnLocal, fnRemote, String.Format("tcp://{0}:10001/RemoteObject.MyRemoteObject", ip));
            cloudFileDictionary.Add(jobID, downloadJob);
            Thread thread = new Thread(new ThreadStart(downloadJob.StartDownload));
            thread.Start();
            Thread.Sleep(100);
        }

        public static void Request_OnDistributeRequest(string fnRemote, string fnLocal, string ip, long jobID)
        {
            DownloadJob downloadJob = new DownloadJob(fnLocal, fnRemote, String.Format("tcp://{0}:10001/RemoteObject.MyRemoteObject", ip));
            cloudFileDictionary.Add(jobID, downloadJob);
        }

        public static void Request_OnStopUploadRequest(long jobID)
        {
            DownloadJob job = ((DownloadJob)cloudFileDictionary[jobID]);
            job.StopDownload();
        }

        public static RemoteObject.JobInfo Request_OnSyncRequest(long jobID)
        {
            DownloadJob job = ((DownloadJob)cloudFileDictionary[jobID]);
            RemoteObject.JobInfo jobInfo = new RemoteObject.JobInfo();
            jobInfo.progress = job.GetProgress();
            jobInfo.downloadSpeed = job.GetProgress();
            return jobInfo;
        }

        public static List<DownloadJob> Request_OnJobListRequest()
        {
            return (new List<DownloadJob>(cloudFileDictionary.Values)); ;
        }

        public static DownloadJob Request_DistributedJob(string jobName)
        {
            Dictionary<long, DownloadJob>.ValueCollection jobList = cloudFileDictionary.Values;
            foreach (DownloadJob djob in jobList)
            {
                if (String.Compare(djob.GetJobName(), jobName, true) == 0)
                {
                    djob.StartDownload();
                    return djob;
                }
            }
            return null;
        }
    }
}
